self pipe trickやsignalfdがなぜ必要なのか
普通に間違ってる可能性はある
「シグナルは非同期に配送される」「シグナルハンドラで可能な処理はasync-signal-safeな呼び出しに限られ,まともなことはできない」と聞いたとき,最初に思いつくのはvolatile sigatomic_tな変数にフラグを書き込んで戻るだけのシグナルハンドラを書くことだと思うtosuke.icon
code:c
volatile sig_atomic_t flag = 0;
void handle(int signum) {
if(signum == SIGINT)
flag = 1;
return;
}
しかしこの方法はうまくいかないことが多い
code:c
while(1) {
// A
if((nfds = select(...)) < 0) {
if(errno != EINTR) {
// エラー処理
}
}
// B
if(flag) {
// シグナル処理
}
// イベント処理
}
このコードだとAからBまでに配送されたシグナルは処理できるが,その後selectが呼び出されるまでの間にもシグナルは配送されうる(シグナルはマスクしない限りありとあらゆる位置で配送されてシグナルハンドラを呼び出す)
このシグナルはこのループでは処理できず,次のイベントが来るかタイムアウトするまで処理が行われない
この問題はselect族が未処理のシグナルがあれば終了するようになればよく,実現する方法はだいたい2種類存在して
1. シグナルをイベントとして処理する
2. シグナルをwaitする箇所でのみ待ち受ける
パイプをイベント機構付き非同期対応キューとして用いる
pselect系のシステムコールはatomicに特定のシグナルマスクが適用された状態でselectとかを呼び出す
sigprocmask (2)で最低限のシグナル以外をブロックし,処理したいシグナルを受け取るようにしたシグナルマスクを適用してpselectを実行すればシグナルハンドラはこの中だけで実行されることが保証される 上記のコードもpselectを使えば正しく動くはず